home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 1 / ETO Development Tools 1.iso / Tools - Objects / C++ / MPW C++ 3.1b1 / Examples / CPlusExamples / TESample.cp < prev    next >
Text File  |  1989-09-29  |  12KB  |  415 lines

  1. /*------------------------------------------------------------------------------
  2. #
  3. #    Apple Macintosh Developer Technical Support
  4. #
  5. #    MultiFinder-Aware Simple TextEdit Sample Application
  6. #
  7. #    CPlusTESample
  8. #
  9. #    TESample.cp    -    C++ source
  10. #
  11. #    Copyright © 1989 Apple Computer, Inc.
  12. #    All rights reserved.
  13. #
  14. #    Versions:    
  15. #            1.10                     07/89
  16. #            1.00                     04/89
  17. #
  18. #    Components:
  19. #            CPlusTESample.make        July 9, 1989
  20. #            TApplicationCommon.h    July 9, 1989
  21. #            TApplication.h            July 9, 1989
  22. #            TDocument.h                July 9, 1989
  23. #            TECommon.h                July 9, 1989
  24. #            TESample.h                July 9, 1989
  25. #            TEDocument.h            July 9, 1989
  26. #            TApplication.cp            July 9, 1989
  27. #            TDocument.cp            July 9, 1989
  28. #            TESample.cp                July 9, 1989
  29. #            TEDocument.cp            July 9, 1989
  30. #            TESampleGlue.a            July 9, 1989
  31. #            TApplication.r            July 9, 1989
  32. #            TESample.r                July 9, 1989
  33. #
  34. #    CPlusTESample is an example application that demonstrates
  35. #    how to initialize the commonly used toolbox managers,
  36. #    operate successfully under MultiFinder, handle desk
  37. #    accessories and create, grow, and zoom windows. The
  38. #    fundamental TextEdit toolbox calls and TextEdit autoscroll
  39. #    are demonstrated. It also shows how to create and maintain
  40. #    scrollbar controls. 
  41. #
  42. #    This version of TESample has been substantially reworked in
  43. #    C++ to show how a "typical" object oriented program could
  44. #    be written. To this end, what was once a single source code
  45. #    file has been restructured into a set of classes which
  46. #    demonstrate the advantages of object-oriented programming.
  47. #
  48. ------------------------------------------------------------------------------*/
  49.  
  50.  
  51. /*
  52. Segmentation strategy:
  53.  
  54.     This program has only one segment, since the issues
  55.     surrounding segmentation within a class's methods have
  56.     not been investigated yet. We DO unload the data
  57.     initialization segment at startup time, which frees up
  58.     some memory 
  59.  
  60. SetPort strategy:
  61.  
  62.     Toolbox routines do not change the current port. In
  63.     spite of this, in this program we use a strategy of
  64.     calling SetPort whenever we want to draw or make calls
  65.     which depend on the current port. This makes us less
  66.     vulnerable to bugs in other software which might alter
  67.     the current port (such as the bug (feature?) in many
  68.     desk accessories which change the port on OpenDeskAcc).
  69.     Hopefully, this also makes the routines from this
  70.     program more self-contained, since they don't depend on
  71.     the current port setting. 
  72.  
  73. Clipboard strategy:
  74.  
  75.     This program does not maintain a private scrap.
  76.     Whenever a cut, copy, or paste occurs, we import/export
  77.     from the public scrap to TextEdit's scrap right away,
  78.     using the TEToScrap and TEFromScrap routines. If we did
  79.     use a private scrap, the import/export would be in the
  80.     activate/deactivate event and suspend/resume event
  81.     routines. 
  82. */
  83.  
  84. #include <Types.h>
  85. #include <QuickDraw.h>
  86. #include <Fonts.h>
  87. #include <Events.h>
  88. #include <Controls.h>
  89. #include <Windows.h>
  90. #include <Menus.h>
  91. #include <TextEdit.h>
  92. #include <Dialogs.h>
  93. #include <Desk.h>
  94. #include <Scrap.h>
  95. #include <ToolUtils.h>
  96. #include <Memory.h>
  97. #include <SegLoad.h>
  98. #include <Files.h>
  99. #include <OSUtils.h>
  100. #include <Traps.h>
  101.  
  102. // our class definitions
  103. #include "TEDocument.h"
  104. #include "TESample.h"
  105.  
  106. // ExtremeNeg and ExtremePos are used to set up wide open rectangles and regions.
  107. const short kExtremeNeg = -32768;
  108. const short kExtremePos = 32767 - 1; // required to address an old region bug
  109.  
  110. // kMaxOpenDocuments is used to determine whether a new document can be opened
  111. // or created. We keep track of the number of open documents, and disable the
  112. // menu items that create a new document when the maximum is reached. If the
  113. // number of documents falls below the maximum, the items are enabled again. */
  114. const short    kMaxOpenDocuments = 1;
  115.     
  116. // Define max and min macros for efficiency.
  117. #define max(a,b)        ((a) > (b) ? (a) : (b))
  118. #define min(a,b)        ((a) < (b) ? (a) : (b))
  119.  
  120. // Our application object, initialized in main(). We make it
  121. // global so our functions which don't belong to any class
  122. // can find the active document.
  123. TESample *gTheApplication;
  124.  
  125. // main is the entrypoint to the program
  126. int main(void)
  127. {
  128.     // Create our application object. This MUST be the FIRST thing
  129.     // done in main(), since it initializes the Toolbox for us.
  130.     gTheApplication = new TESample;
  131.     if (gTheApplication == nil)        // if we couldn't allocate object (impossible!?)
  132.       return 0;                        // go back to Finder
  133.     
  134.     // Start our main event loop running. This won't return until user quits
  135.     gTheApplication->EventLoop();
  136.  
  137.     // We always return a value, like good little ANSI worshippers
  138.     return 0;
  139. }
  140.  
  141. // the constructor for our class, called automatically when we create
  142. // an instance of this class. In this particular case, we only want
  143. // one instance since the constructor does all the menu setups and
  144. // creates our (untitled) document.
  145. TESample::TESample(void)
  146. {
  147.     Handle    menuBar;
  148.  
  149.     // read menus into menu bar
  150.     menuBar = GetNewMBar(rMenuBar);
  151.     // install menus
  152.     SetMenuBar(menuBar);
  153.     DisposHandle(menuBar);
  154.     // add DA names to Apple menu
  155.     AddResMenu(GetMHandle(mApple), 'DRVR');
  156.     DrawMenuBar();
  157.  
  158.     // create empty mouse region
  159.     fMouseRgn = NewRgn();
  160.     // create a single empty document
  161.     DoNew();
  162.     // make sure we have a valid cursor region
  163.     AdjustCursor();
  164. }
  165.  
  166. // Tell TApplication class how much heap we need
  167. long TESample::HeapNeeded(void)
  168. {
  169.     return (kMinSize * 1024);
  170. }
  171.  
  172. // Calculate a sleep value for WaitNextEvent. This takes into account the things
  173. // that DoIdle does with idle time.
  174.  
  175. unsigned long TESample::SleepVal(void)
  176. {
  177.     unsigned long sleep;
  178.  
  179.     sleep = kMaxSleepTime;                // default value for sleep
  180.     // if we aren't in background, let document tell us how long to sleep
  181.     if ((!fInBackground) && (fCurDoc != nil))
  182.       sleep = min(sleep,fCurDoc->CalcIdle());
  183.     return sleep;
  184. }
  185.  
  186. // This is called whenever we get a null event et al.
  187. // It takes care of necessary periodic actions. For this program,
  188. // it calls TEIdle.
  189.  
  190. void TESample::DoIdle(void)
  191. {
  192.     TEDocument* fTECurDoc = (TEDocument*) fCurDoc;
  193.  
  194.     if ( fTECurDoc != nil )
  195.       fTECurDoc->DoIdle();
  196. } // DoIdle
  197.  
  198. // Change the cursor's shape, depending on its position. This also calculates a
  199. // region that includes the cursor for WaitNextEvent.
  200.  
  201. void TESample::AdjustCursor(void)
  202. {
  203.     TEDocument* fTECurDoc = (TEDocument*) fCurDoc;
  204.  
  205.     // notice that we don't change cursor if front window isn't ours
  206.     if ( (!fInBackground) && (fTECurDoc != nil) )
  207.       {
  208.         RgnHandle    arrowRgn;
  209.         RgnHandle    iBeamRgn;
  210.         Point        mouse;
  211.         
  212.         // get mouse location and convert to global coordinates
  213.         GetMouse(&mouse);
  214.         LocalToGlobal(&mouse);
  215.  
  216.         // calculate regions for different cursor shapes
  217.         arrowRgn = NewRgn();
  218.         iBeamRgn = NewRgn();
  219.         // start arrowRgn wide open
  220.         SetRectRgn(arrowRgn, kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos);
  221.         // calculate iBeamRgn
  222.         fTECurDoc->GetVisTERgn(iBeamRgn);
  223.         // subtract iBeamRgn from arrowRgn 
  224.         DiffRgn(arrowRgn, iBeamRgn, arrowRgn);
  225.  
  226.         // change the cursor and the region parameter 
  227.         if (PtInRgn(mouse, iBeamRgn))
  228.           {
  229.             SetCursor(*GetCursor(iBeamCursor));
  230.             CopyRgn(iBeamRgn, fMouseRgn);
  231.           }
  232.         else
  233.           {
  234.             SetCursor(&qd.arrow);
  235.             CopyRgn(arrowRgn, fMouseRgn);
  236.           }
  237.         // get rid of regions we don't need anymore
  238.         DisposeRgn(arrowRgn);
  239.         DisposeRgn(iBeamRgn);
  240.       }
  241. } // AdjustCursor
  242.  
  243. // Enable and disable menus based on the current state. The
  244. // user can only select enabled menu items. We set up all the
  245. // menu items before calling MenuSelect or MenuKey, since
  246. // these are the only times that a menu item can be selected.
  247. // Note that MenuSelect is also the only time the user will
  248. // see menu items. This approach to deciding what enable/
  249. // disable state a menu item has the advantage of
  250. // concentrating all the decision-making in one routine, as
  251. // opposed to being spread throughout the application. Other
  252. // application designs may take a different approach that may
  253. // or may not be as valid. 
  254.  
  255. void TESample::AdjustMenus(void)
  256. {
  257.     WindowPtr    frontmost;
  258.     MenuHandle    menu;
  259.     long        offset;
  260.     Boolean        undo;
  261.     Boolean        cutCopyClear;
  262.     Boolean        paste;
  263.     TEDocument* fTECurDoc = (TEDocument*) fCurDoc;
  264.  
  265.     frontmost = FrontWindow();
  266.  
  267.     menu = GetMHandle(mFile);
  268.     if ( fDocList->NumDocs() < kMaxOpenDocuments )
  269.       EnableItem(menu, iNew);            // New is enabled when we can open more documents 
  270.     else DisableItem(menu, iNew);
  271.     if ( frontmost != (WindowPtr) nil )    // Close is enabled when there is a window to close 
  272.       EnableItem(menu, iClose);
  273.     else DisableItem(menu, iClose);
  274.  
  275.     menu = GetMHandle(mEdit);
  276.     undo = false;
  277.     cutCopyClear = false;
  278.     paste = false;
  279.     if (frontmost != nil)
  280.       {
  281.         if (fTECurDoc == nil)
  282.           {
  283.             undo = true;                // all editing is enabled for DA windows 
  284.             cutCopyClear = true;
  285.             paste = true;
  286.           }
  287.         else
  288.           {
  289.             // Cut, Copy, and Clear is enabled for app. windows with selections 
  290.             if ( fTECurDoc->HaveSelection() )
  291.               cutCopyClear = true;
  292.             // If we have any TEXT in the scrap, enable paste
  293.             if ( GetScrap(nil, 'TEXT', &offset) )
  294.                 paste = true; 
  295.           }
  296.       }
  297.     if ( undo )
  298.       EnableItem(menu, iUndo);
  299.     else DisableItem(menu, iUndo);
  300.     if ( cutCopyClear )
  301.       {
  302.         EnableItem(menu, iCut);
  303.         EnableItem(menu, iCopy);
  304.         EnableItem(menu, iClear);
  305.       } 
  306.     else
  307.       {
  308.         DisableItem(menu, iCut);
  309.         DisableItem(menu, iCopy);
  310.         DisableItem(menu, iClear);
  311.       }
  312.     if ( paste )
  313.         EnableItem(menu, iPaste);
  314.     else DisableItem(menu, iPaste);
  315. } // AdjustMenus
  316.  
  317.  
  318. // This is called when an item is chosen from the menu bar (after calling
  319. // MenuSelect or MenuKey). It does the right thing for each command.
  320.  
  321. void TESample::DoMenuCommand(short menuID, short menuItem)
  322. {
  323.     short        itemHit;
  324.     Str255        daName;
  325.     short        daRefNum;
  326.     WindowPtr    window;
  327.     TEDocument* fTECurDoc = (TEDocument*) fCurDoc;
  328.  
  329.     window = FrontWindow();
  330.     switch ( menuID )
  331.       {
  332.         case mApple:
  333.             switch ( menuItem )
  334.               {
  335.                 case iAbout:        // bring up alert for About 
  336.                     itemHit = Alert(rAboutAlert, nil);
  337.                     break;
  338.                 default:            // all non-About items in this menu are DAs et al 
  339.                     GetItem(GetMHandle(mApple), menuItem, daName);
  340.                     daRefNum = OpenDeskAcc(daName);
  341.                     break;
  342.               }
  343.             break;
  344.         case mFile:
  345.             switch ( menuItem )
  346.               {
  347.                 case iNew:
  348.                     DoNew();
  349.                     break;
  350.                 case iClose:
  351.                     if (fTECurDoc != nil)
  352.                       {
  353.                         fDocList->RemoveDoc(fTECurDoc);
  354.                         fTECurDoc->DoClose();
  355.                       }
  356.                     else CloseDeskAcc(((WindowPeek) fWhichWindow)->windowKind);
  357.                     // make sure our current document/window references are valid
  358.                     fWhichWindow = FrontWindow();
  359.                     if (fWhichWindow != nil)
  360.                       {
  361.                         fCurDoc = fDocList->FindDoc(fWhichWindow);
  362.                         SetPort(fWhichWindow);
  363.                       }
  364.                     else fCurDoc = nil;
  365.                     break;
  366.                 case iQuit:
  367.                     Terminate();
  368.                     break;
  369.               }
  370.             break;
  371.         case mEdit:                    // call SystemEdit for DA editing & MultiFinder 
  372.             if ( !SystemEdit(menuItem-1) )
  373.               {
  374.                 switch ( menuItem )
  375.                   {
  376.                     case iCut:
  377.                         fTECurDoc->DoCut();
  378.                         break;
  379.                     case iCopy:
  380.                         fTECurDoc->DoCopy();
  381.                         break;
  382.                     case iPaste:
  383.                         fTECurDoc->DoPaste();
  384.                         break;
  385.                     case iClear:
  386.                         fTECurDoc->DoClear();
  387.                         break;
  388.                    }
  389.               }
  390.             break;
  391.       }
  392.     HiliteMenu(0);                    // unhighlight what MenuSelect (or MenuKey) hilited 
  393. } // DoMenuCommand
  394.  
  395. // Create a new document and window. 
  396.  
  397. void TESample::DoNew(void)
  398. {
  399.     TEDocument* tDoc;
  400.  
  401.     tDoc = new TEDocument(rDocWindow);
  402.     // if we didn't get an allocation error, add it to list
  403.     if (tDoc != nil)
  404.       fDocList->AddDoc(tDoc);
  405. } // DoNew
  406.  
  407. // Clean up the application and exits. You might want to close all
  408. // of your documents (and ask the user to save them) here.
  409.  
  410. void TESample::Terminate(void)
  411. {
  412.     ExitLoop();
  413. } // Terminate
  414.  
  415.